/*
 * ReactionBuilder.cpp
 *
 *  Created on: 15 Jul 2011
 *      Author: al2010
 */

#include "ReactionBuilder.h"

// C++ includes
#include <iostream>
using namespace std;

// GeoReact includes
#include "Database.h"
#include "MineralRate/MineralRate.h"

const Reaction ReactionBuilder::CreateReaction(const SpeciesMap& speciesMap, const String& reactantName)
{
	// Check the type of the species and create the appropriate reaction
	if(Database::GetInstance().GetSpeciesInfo(reactantName).HasTag("basis"))
		return CreateBasisReaction(speciesMap, reactantName);
	else
	if(Database::GetInstance().GetSpeciesInfo(reactantName).HasTag("mineral"))
		return CreateMineralReaction(speciesMap, reactantName);
	else
		return CreateReactionFromDatabase(speciesMap, reactantName);
}

const Reaction ReactionBuilder::CreateBasisReaction(const SpeciesMap& speciesMap, const String& reactantName)
{
	// The reaction object to be setup for a basis species
	Reaction reaction;
	
	// The reactant of the reaction
	Reaction::Reactant reactant = {reactantName, speciesMap[reactantName]};
	
	// The products of the reaction, which consists of only one species: the reactant itself 
	vector<Reaction::Product> products = { {reactantName, speciesMap[reactantName], 1.0} }; 
	
	// The equilibrium constant data of the basis reaction, which happens to be K = 1.0 for all temperatures
	Reaction::EquilibriumConstantData eqData = { {0.0}, {25.0} }; // Assume temperature is 25.0 for the unit equilibrium constant 
	
	// The the attributes of the reaction
	reaction.SetReactant(reactant);
	reaction.SetProducts(products);
	reaction.SetEquilibriumConstantData(eqData);
	
	// Return the basis reaction object
	return reaction;
}

const Reaction ReactionBuilder::CreateReactionFromDatabase(const SpeciesMap& speciesMap, const String& reactantName)
{
	// A reference to the database containing all the supported species and reactions
	const Database& db = Database::GetInstance();
	
	// Get an optional object to the information data of the reaction whose reactant is the given species
	const ReactionInfo reactionInfo = db.GetReactionInfo(reactantName);
	
	// Create the reaction object for the given mineral
	Reaction reaction;
	
	// The reactant of the reaction
	Reaction::Reactant reactant = {reactionInfo.reactant, speciesMap[reactionInfo.reactant]};
	
	// The products of the reaction
	vector<Reaction::Product> products(reactionInfo.products.size()); 
	
	for(uint i = 0; i < products.size(); ++i)
		products[i] = {reactionInfo.products[i], speciesMap[reactionInfo.products[i]], reactionInfo.stoichiometries[i]};
	
	// The equilibrium constant data of the reaction
	Reaction::EquilibriumConstantData eqData = {reactionInfo.logKi, reactionInfo.Ti};
	
	// The the attributes of the reaction
	reaction.SetReactant(reactant);
	reaction.SetProducts(products);
	reaction.SetEquilibriumConstantData(eqData);
	
	// Return the reaction object
	return reaction;
}

const Reaction ReactionBuilder::CreateMineralReaction(const SpeciesMap& speciesMap, const String& mineralName)
{
	// Create the reaction object for the given mineral
	Reaction mineralReaction = CreateReactionFromDatabase(speciesMap, mineralName);
	
	// Set the mineral reaction mass rate
	mineralReaction.SetMassRate( GeneralMineralReactionMassRate(speciesMap, mineralName) );

	return mineralReaction;
}
